(function() {
    var pub = Ext.lib.Ajax, activeX = ['MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP'], CONTENTTYPE = 'Content-Type';

    // private
    function setHeader(o) {
        var conn = o.conn, prop;

        function setTheHeaders(conn, headers) {
            for (prop in headers) {
                if (headers.hasOwnProperty(prop)) {
                    conn.setRequestHeader(prop, headers[prop]);
                }
            }
        }

        if (pub.defaultHeaders) {
            setTheHeaders(conn, pub.defaultHeaders);
        }

        if (pub.headers) {
            setTheHeaders(conn, pub.headers);
            delete pub.headers;
        }
    }

    // private
    function initHeader(label, value) {
        (pub.headers = pub.headers || {})[label] = value;
    }

    // private
    function createResponseObject(o, callbackArg) {
        var headerObj = {}, headerStr, conn = o.conn, t, s;

        try {
            headerStr = o.conn.getAllResponseHeaders();
            Ext.each(headerStr.replace(/\r\n/g, '\n').split('\n'), function(v) {
                t = v.indexOf(':');
                if (t >= 0) {
                    s = v.substr(0, t).toLowerCase();
                    if (v.charAt(t + 1) == ' ') {
                        ++t;
                    }
                    headerObj[s] = v.substr(t + 1);
                }
            });
        } catch (e) {
        }

        return {
            tId: o.tId,
            status: conn.status,
            statusText: conn.statusText,
            getResponseHeader: function(header) {
                return headerObj[header.toLowerCase()];
            },
            getAllResponseHeaders: function() {
                return headerStr
            },
            responseText: conn.responseText,
            responseXML: conn.responseXML,
            argument: callbackArg
        };
    }

    // private
    function syncRequest(method, uri, callback, postData) {
        var o = getConnectionObject() || null;

        if (o) {
            o.conn.open(method, uri, false);

            if (pub.useDefaultXhrHeader) {
                initHeader('X-Requested-With', pub.defaultXhrHeader);
            }

            if (postData && pub.useDefaultHeader && (!pub.headers || !pub.headers[CONTENTTYPE])) {
                initHeader(CONTENTTYPE, pub.defaultPostHeader);
            }

            if (pub.defaultHeaders || pub.headers) {
                setHeader(o);
            }

            o.conn.send(postData || null);
        }
        return o;
    }

    // private
    function getConnectionObject() {
        var o;

        try {
            if (o = createXhrObject(pub.transactionId)) {
                pub.transactionId++;
            }
        } catch (e) {
        } finally {
            return o;
        }
    }

    // private
    function createXhrObject(transactionId) {
        var http;

        try {
            http = new XMLHttpRequest();
        } catch (e) {
            for (var i = 0; i < activeX.length; ++i) {
                try {
                    http = new ActiveXObject(activeX[i]);
                    break;
                } catch (e) {
                }
            }
        } finally {
            return {
                conn: http,
                tId: transactionId
            };
        }
    }

    pub.syncRequest = function(method, uri, cb, data, options) {
        if (options) {
            var me = this, xmlData = options.xmlData, jsonData = options.jsonData, hs, o, responseObject;

            Ext.applyIf(me, options);

            if (xmlData || jsonData) {
                hs = me.headers;
                if (!hs || !hs[CONTENTTYPE]) {
                    initHeader(CONTENTTYPE, xmlData ? 'text/xml' : 'application/json');
                }
                data = xmlData || (!Ext.isPrimitive(jsonData) ? Ext.encode(jsonData) : jsonData);
            }

            o = syncRequest(method || options.method || "POST", uri, cb, data);

            responseObject = createResponseObject(o, cb.argument);
            if (cb.success) {
                if (!cb.scope) {
                    cb.success(responseObject);
                } else {
                    cb.success.apply(cb.scope, [responseObject]);
                }
            }
        }
    };
})();
